/* 
 * File:   FiguraFactory.cpp
 * Author: mm021791
 * 
 * Created on 26 de septiembre de 2012, 13:12
 */

#include "FiguraFactory.h"

#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <fstream>

#include "BMPHeader.h"

using namespace std;
using namespace TP::Grafica::Componentes;
using namespace TP::Grafica::Renderizado;

FiguraFactory::FiguraFactory(){}

FiguraFactory::~FiguraFactory() {}

Figura* FiguraFactory::crear(const string& pDescriptor) throw (FiguraFactoryException&) {
    
    Figura* figura = NULL;
    Posicion* posicion = NULL;
    
    try
    {
        if ("" != pDescriptor)
        {
            char tipo = this->getTipo(pDescriptor);
            posicion = this->getPosicion(pDescriptor);

            this->cargarTemplate(figura, tipo, posicion);
        }
        return figura;        
    }
    catch (FiguraFactoryException &pEx)
    {
        if (NULL != posicion) delete posicion;
        
        string msg = "";
        
        msg += "No se puede crear la figura (";
        msg += pDescriptor;
        msg += ").  ";
        
        pEx.expandirMensaje(msg.c_str());
        throw;
    }
    catch (exception& pEx){

        if (NULL != posicion) delete posicion;
        
        string msg = "";
        
        msg += "No se puede crear la figura (";
        msg += pDescriptor;
        msg += ").  ";
        msg += pEx.what();
        
        throw FiguraFactoryException (msg.c_str());
    }
}

void FiguraFactory::cargarTemplate (Figura* &pFigura, char pTipo, Posicion* pPosicion) throw(FiguraFactoryException&) {
    
    try
    {
        // Defino la referencia al template correspondiente a la figura que hace
        // referencia el descriptor.
        
        string path = "";
        path += pTipo;
        path += "_";
        path += this->getRotacion (pPosicion);
        path += ".bmp";

        // Levanto el archivo correspondiente al template.
        
        ifstream file (path.c_str(), std::iostream::binary);

        if (file.is_open())
        {
            // Inicializo la figura.
            pFigura = new Figura(pTipo,  pPosicion);
            file >> *pFigura;

            // Tras levantar la informacion de la figura cierro el archivo.
            file.close();
        }
        else
        {
            string message = "No se puede abrir el archivo ";
            message += path;

            throw FiguraFactoryException ( message.c_str());
        }
    }
    catch (FiguraException& pEx)
    {
        throw FiguraFactoryException (pEx.what());
    }
    catch (FiguraFactoryException& pEx)
    {
        pEx.expandirMensaje("Fallo al cargar el template.  ");
        throw;
    }
    catch (exception& pEx)
    {
        string msg = "Fallo al cargar el template.  ";
        msg += pEx.what();
        
        throw FiguraFactoryException (msg.c_str());
    }
}

char FiguraFactory::getTipo (const string& pDescriptor) throw (FiguraFactoryException&) {
    
    try
    {
        // El primer caracter del descriptor indica el tipo de figura.
        return pDescriptor.substr(0, 1)[0];
    }
    catch (exception& pEx)
    {
        string msg = "No se puede leer el tipo del descriptor.";
        msg += pEx.what();
        
        throw FiguraFactoryException (msg.c_str());
    }
}

string FiguraFactory::getRotacion(Posicion* pPosicion) throw (FiguraFactoryException&) {

    try
    {
        short int rotacion = ROTACION_NULA;

        switch (pPosicion->getOrientacion())
        {
            case ROTACION_0H:
                rotacion = 0;
                break;

            case ROTACION_90H:
                rotacion = 90;
                break;

            case ROTACION_180H:
                rotacion = 180;
                break;

            case ROTACION_90HN:
                rotacion = 270;
                break;
        }
        stringstream stream;
        stream << rotacion;
        return stream.str();
    }
    catch (exception& pEx)
    {
        string msg = "No se puede obtener la rotacion del descriptor.  ";
        msg += pEx.what();
        
        throw FiguraFactoryException (msg.c_str());
    }
}

Posicion* FiguraFactory::getPosicion(const string& pDescriptor) throw (FiguraFactoryException&) {

    try
    {
        unsigned long int fila = 0
                        , columna = 0;
        short int orientacion = ROTACION_NULA;

        string word;
        stringstream stream(pDescriptor);
        
        // Descarto el tipo de figura del descriptor.
        getline (stream, word, ':');
        int cur = 1;
        
        while( getline(stream, word, ',') )
        {
            switch (cur)
            {
                case 1:
                    columna = strtoul(word.c_str(), NULL, 10);
                    break;
                case 2:
                    fila = strtoul(word.c_str(), NULL, 10);
                    break;
                case 3:
                    orientacion = strtoul(word.c_str(), NULL, 10);
                    break;
            }
            cur++;
        }

        return new Posicion (fila, columna, orientacion);
    
    }
    catch (exception& pEx)
    {
        string msg = "No se puede obtener la posicion del descriptor. ";
        msg += pEx.what();

        throw FiguraFactoryException (msg.c_str());
    }
}

